package leveup.lock;

import org.junit.Test;
import org.openjdk.jol.info.ClassLayout;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 不同锁状态下的对象内存布局
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/08/28 下午 02:26
 */
public class ObjectStateTest {

    /**
     * 无锁状态测试
     */
    @Test
    public void testNoLock() {
        Object obj = new Object();
        int hashCode = obj.hashCode();
        //463345942
        System.out.println(hashCode);
        //1b9e1916
        System.out.println(Integer.toHexString(hashCode));
//        11011100111100001100100010110
        System.out.println(Integer.toBinaryString(hashCode));

//        0     4        (object header)                           01 16 19 9e (【0】<0000> |0|01| {00010110 00011001 10011110}) (-1642523135)
//        4     4        (object header)                           1b 00 00 00 (【0】{0011011} 【00000000 00000000 00000000】) (27)
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }

    /**
     * 偏向锁状态测试
     */
    @Test
    public void testBiasedLock() throws InterruptedException {
        final Object obj = new Object();
        CountDownLatch latch = new CountDownLatch(3);
        AtomicInteger cnt = new AtomicInteger(20);

        for (int i = 1; i <= 3; i++) {
            new Thread(() -> {
                try {
                    while (true) {
                        synchronized (obj) {
                            if (cnt.get() == 0) {
                                break;
                            }
                            cnt.set(cnt.get() - 1);
                            System.out.println(Thread.currentThread().getName() + ":remain " + (cnt.get()));
                        }
                    }
                } finally {
                    latch.countDown();
                }
            }, "t" + i).start();
        }

        latch.await();
    }

    /**
     * 通过添加虚拟机参数 -XX:BiasedLockingStartupDelay=0 来使得偏向锁立刻生效
     */
    @Test
    public void testImmediatelyBiasedLock() throws Exception {
        //如果不加-XX:BiasedLockingStartupDelay=0 ，获取锁之前让线程运行4s以上也能达到目的
        //Thread.sleep(5000);

        Object obj = new Object();
        synchronized (obj) {
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }

    /**
     * 通过添加虚拟机参数 -XX:-UseBiasedLocking 来关闭使用偏向锁，
     * 这样当进入同步代码块时MarkWord状态由 无锁 立马变为 轻量级锁
     */
    @Test
    public void testLightLock() {

        Object obj = new Object();
        synchronized (obj) {
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }

    /**
     * 当线程竞争激烈时，锁会升级为重量级锁
     */
    @Test
    public void testHeavyweightLock() throws Exception {

        final Object obj = new Object();
        CountDownLatch latch = new CountDownLatch(50);
        AtomicInteger counter = new AtomicInteger(50);

        ExecutorService threadPool = Executors.newFixedThreadPool(50);

        for (int i = 0; i < 50; i++) {
            threadPool.submit(() -> {
                try {
                    synchronized (obj) {
                        System.out.println(Thread.currentThread().getName() + " come in ---");
                        int val = counter.decrementAndGet();
                        if (val == 0) {
                            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
                        }
                    }
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await();
    }

    /**
     * 调用hashcode后，对象不会再进入偏向锁状态，而是直接进入轻量级锁状态
     */
    @Test
    public void hashCodeCalledBeforeTest() throws Exception{
        //线程休眠5s保证偏向锁开启
        Thread.sleep(5000);
        Object obj = new Object();

        //调用hashCode()
        obj.hashCode();

        synchronized (obj){
            //锁标志位为00,处于轻量级锁状态
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }

    /**
     * 偏向锁状态下调用hashCode(),立马撤销偏向锁状态，直接膨胀为重量级锁
     */
    @Test
    public void hashCodeCalledInBiasedLock() throws Exception{
        //线程休眠5s保证偏向锁开启
        Thread.sleep(5000);
        Object obj = new Object();

        synchronized (obj){
            //锁标志位为101,处于偏向锁
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            //偏向锁内状态下调用hashCode()
            obj.hashCode();
            //锁标志位为10,处于重量级锁状态
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }
}
